﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Warp9
{
    class Camera
    {
        private int worldSize;
        private Vector3 position;
        private Vector3 target;
        private Vector3 rotation;
        private Vector3 offset;
        private Vector3 offsetVelocity;
        private float speed;
        private Matrix cameraRotation;
        public string Message;
        public Matrix viewMatrix, projectionMatrix;
        public float zoomLevel;
        public Camera()
        {
            ResetCamera();
        }

        public Camera(int sizeOfWorld)
        {
            worldSize = sizeOfWorld;
            ResetCamera();
        }

        public void ResetCamera()
        {
            position = new Vector3(0, 0f, 50);
            target = new Vector3(0, 0f, 0);
            rotation = new Vector3(0f, 0f, 0f);
            zoomLevel = 2f;
            offset = new Vector3(0f, -60f, 50f-(5000f/worldSize)*zoomLevel);
            speed = 0.06f + (0.06f / worldSize);
            cameraRotation = Matrix.Identity;

            viewMatrix = Matrix.Identity;
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), 6f / 4f, 0.5f, 500f);
        }

        public void ResetCamera(Vector3 offset)
        {
            ResetCamera();
            position += offset;
            target += offset;
        }

        public void ResetCamera(int newWorldSize)
        {
            worldSize = newWorldSize;
            speed = 0.06f + (0.06f / worldSize);
            offset.Z = 50f - (5000f / worldSize) * zoomLevel;
        }

        public void Update()
        {
            HandleInput();
            UpdateViewMatrix();
            Message = speed.ToString();
        }

        private void HandleInput()
        {
            KeyboardState state = Keyboard.GetState();
            float localSpeed = speed;
            if (state.IsKeyDown(Keys.LeftShift))
            {
                localSpeed *= 3f;
            }

            if (state.IsKeyDown(Keys.W))
            {
                offsetVelocity.Y += (-localSpeed / 2) / 10;
            }
            if (state.IsKeyDown(Keys.S))
            {
                offsetVelocity.Y += (localSpeed / 2) / 10;
            }
            if (state.IsKeyDown(Keys.A))
            {
                offsetVelocity.Z += (-localSpeed / (worldSize / 2));
            }
            if (state.IsKeyDown(Keys.D))
            {
                offsetVelocity.Z += (localSpeed / (worldSize / 2));
            }
            if (state.IsKeyDown(Keys.Add))
            {
                offset.Z += localSpeed*4f;
            }
            if (state.IsKeyDown(Keys.Subtract))
            {
                    offset.Z += -localSpeed*4f;
            }

            rotation.Z = offsetVelocity.Z;

            offset.Y += offsetVelocity.Y;

            DiminishOffsets();
        }

        private void DiminishOffsets()
        {
            if (Math.Abs(offsetVelocity.Z) > 0.000001f)
            {
                offsetVelocity.Z *= 0.925f;
            }
            else
            {
                offsetVelocity.Z = 0;
            }
            if (Math.Abs(offsetVelocity.Y) > 0.000001f)
            {
                offsetVelocity.Y *= 0.8875f;
            }
            else
            {
                offsetVelocity.Y = 0;
            }
        }

        public void Translate(Vector3 newTranslate)
        {
            target += newTranslate;
            position += newTranslate;
        }

        private void UpdateViewMatrix()
        {
            cameraRotation.Forward.Normalize();
            cameraRotation.Up.Normalize();
            cameraRotation.Right.Normalize();
            cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Forward, rotation.Z);
            rotation = Vector3.Zero;
            target = position + cameraRotation.Forward;

            viewMatrix = Matrix.CreateLookAt(position, target,cameraRotation.Up);
            viewMatrix *= Matrix.CreateTranslation(offset);
        }
    }
}
